/**************************************************************
* M3D_VMX.HPP   Crossplatform VMX support implementation
**************************************************************/



//
// Vector Load & store
//

/*************************************************************
* vmxVectStoreA ()
*************************************************************/
__INLINE void vmxVectStoreA (vmxV v, float *dst) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   XMStoreFloat4A((XMFLOAT4A*)dst, v);
#endif
#if defined(_AP_PS3)
   vec_st(v.get128(), 0, dst);
#endif
   return;
}
/*************************************************************
* vmxVectStoreUA ()
*************************************************************/
__INLINE void vmxVectStoreUA (vmxV v, float *dst) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   XMStoreFloat4((XMFLOAT4*)dst, v);
#endif
#if defined(_AP_PS3)
   vec_store_unaligned(v.get128(), dst);
#endif
   return;
}
/*************************************************************
* vmxVectStore3UA ()
*************************************************************/
__INLINE void vmxVectStore3UA (vmxV v, float *dst) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   XMStoreFloat3((XMFLOAT3*)dst, v);
#endif
#if defined(_AP_PS3)
   vec_store3_unaligned(v.get128(), dst);
#endif
   return;
}
/*************************************************************
* vmxVectLoadA ()
*************************************************************/
__INLINE vmxV vmxVectLoadA (float *src) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMLoadFloat4A((XMFLOAT4A*)src);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_ld(0, src));
#endif
}
/*************************************************************
* vmxVectLoadUA ()
*************************************************************/
__INLINE vmxV vmxVectLoadUA (float *src) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMLoadFloat4((XMFLOAT4*)src);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_load_unaligned(src, 0));
#endif
}
/*************************************************************
* vmxVectLoad3UA ()
*************************************************************/
__INLINE vmxV vmxVectLoad3UA (float *src) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMLoadFloat3((XMFLOAT3*)src);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_insert(0.f, (vec_float4)vec_load_unaligned(src, 0), 0));
#endif
}
/*************************************************************
* vmxLoadShort4 ()
*************************************************************/
__INLINE vmxV vmxLoadShort4 (const INT16 *src) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMLoadShort4((XMSHORT4*)src);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_ctf(vec_unpackh(vec_load_unaligned(src)), 0));
#endif
}

//
// Integer in vector
//
/*************************************************************
* vmxVectSetInt ()
*************************************************************/
__INLINE vmxV vmxVectSetInt (int   x, int   y, int   z, int   w)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSetInt(x, y, z, w);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)((vec_int4) { x, y, z, w }));
#endif
}
/*************************************************************
* vmxVectConvertIntToFloat ()
*************************************************************/
#if defined(_AP_PC) || defined(_AP_XENON)
#define vmxVectConvertIntToFloat(v, divExp) XMConvertVectorIntToFloat(v, divExp)
#endif
#if defined(_AP_PS3)
#define vmxVectConvertIntToFloat(v, divExp) Aos::Vector4(vec_ctf((vec_int4)v.get128(), divExp))
#endif
/*************************************************************
* vmxVectConvertFloatToInt()
*************************************************************/
#if defined(_AP_PC) || defined(_AP_XENON)
#define vmxVectConvertFloatToInt(v, mulExp) XMConvertVectorFloatToInt(v, mulExp)
#endif
#if defined(_AP_PS3)
#define vmxVectConvertFloatToInt(v, mulExp) Aos::Vector4(vec_cts((vec_int4)v.get128(), mulExp))
#endif


//
// Vector Set & Get
//
/*************************************************************
* vmxVectSet ()
*************************************************************/
__INLINE vmxV vmxVectSet (float x, float y, float z, float w) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSet(x, y, z, w);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(x, y, z, w);
#endif
}
/*************************************************************
* vmxVectSet ()
*************************************************************/
__INLINE vmxV vmxVectSet (int   x, int   y, int   z, int   w)
{
   return vmxVectConvertIntToFloat(vmxVectSetInt(x, y, z, w), 0);
}
/*************************************************************
* vmxVectSetX ()
*************************************************************/
__INLINE vmxV vmxVectSetX (vmxV v, float x)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSetX(v, x);
#endif
#if defined(_AP_PS3)
   return v.setX(x);
#endif
}
/*************************************************************
* vmxVectSetY ()
*************************************************************/
__INLINE vmxV vmxVectSetY (vmxV v, float y)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSetY(v, y);
#endif
#if defined(_AP_PS3)
   return v.setY(y);
#endif
}
/*************************************************************
* vmxVectSetZ ()
*************************************************************/
__INLINE vmxV vmxVectSetZ (vmxV v, float z)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSetZ(v, z);
#endif
#if defined(_AP_PS3)
   return v.setZ(z);
#endif
}
/*************************************************************
* vmxVectSetW ()
*************************************************************/
__INLINE vmxV vmxVectSetW (vmxV v, float w)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSetW(v, w);
#endif
#if defined(_AP_PS3)
   return v.setW(w);
#endif
}
/*************************************************************
* vmxVectGetX ()
*************************************************************/
__INLINE float vmxVectGetX (vmxV v)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorGetX(v);
#endif
#if defined(_AP_PS3)
   return v.getX();
#endif
}
/*************************************************************
* vmxVectGetY ()
*************************************************************/
__INLINE float vmxVectGetY (vmxV v)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorGetY(v);
#endif
#if defined(_AP_PS3)
   return v.getY();
#endif
}
/*************************************************************
* vmxVectGetZ ()
*************************************************************/
__INLINE float vmxVectGetZ (vmxV v)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorGetZ(v);
#endif
#if defined(_AP_PS3)
   return v.getZ();
#endif
}
/*************************************************************
* vmxVectGetW ()
*************************************************************/
__INLINE float vmxVectGetW (vmxV v)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorGetW(v);
#endif
#if defined(_AP_PS3)
   return v.getW();
#endif
}


//
// Vector Rounding
//
/*************************************************************
* vmxVectFloor ()
*************************************************************/
__INLINE vmxV vmxVectFloor (vmxV v) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorFloor(v);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_floor(v.get128()));
#endif
}
/*************************************************************
* vmxVectCeiling ()
*************************************************************/
__INLINE vmxV vmxVectCeiling (vmxV v) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorCeiling (v);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_ceil(v.get128()));
#endif
}
/*************************************************************
* vmxVectRound ()
*************************************************************/
__INLINE vmxV vmxVectRound (vmxV v) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorRound(v);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_round(v.get128()));
#endif
}
/*************************************************************
* vmxVectTrunc ()
*************************************************************/
__INLINE vmxV vmxVectTrunc (vmxV v) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorTruncate(v);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_trunc(v.get128()));
#endif
}


//
// Vector Math ops
//
/*************************************************************
* vmxVectAbs ()
*************************************************************/
__INLINE vmxV vmxVectAbs (vmxV v)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorAbs(v);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_abs(v.get128()));
#endif
}
/*************************************************************
* vmxVectNegate ()
*************************************************************/
__INLINE vmxV vmxVectNegate (vmxV v)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorNegate(v);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)negatef4(v.get128()));
#endif
}
/*************************************************************
* vmxVectAdd ()
*************************************************************/
__INLINE vmxV vmxVectAdd (vmxV a, vmxV b)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorAdd(a, b);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_add(a.get128(), b.get128()));
#endif
}
/*************************************************************
* vmxVectSub ()
*************************************************************/
__INLINE vmxV vmxVectSub (vmxV a, vmxV b)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSubtract(a, b);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_sub(a.get128(), b.get128()));
#endif
}
/*************************************************************
* vmxVectMul ()
*************************************************************/
__INLINE vmxV vmxVectMul (vmxV a, vmxV b)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorMultiply(a, b);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_madd(a.get128(), b.get128(), (vec_float4)(0.0f)));
#endif
}
/*************************************************************
* vmxVectDivide ()
*************************************************************/
__INLINE vmxV vmxVectDivide (vmxV a, vmxV b)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorDivide(a, b);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(divf4(a.get128(), b.get128()));
#endif
}

/*************************************************************
* vmxVectMadd ()
*************************************************************/
__INLINE vmxV vmxVectMadd (vmxV a, vmxV b, vmxV c)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorMultiplyAdd(a, b, c);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_madd(a.get128(), b.get128(), c.get128()));
#endif
}
/*************************************************************
* vmxVectSqrt ()
*************************************************************/
__INLINE vmxV vmxVectSqrt (vmxV a)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSqrt(a);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(sqrtf4(a.get128()));
#endif
}
/*************************************************************
* vmxVectSqrtEst ()
*************************************************************/
__INLINE vmxV vmxVectSqrtEst (vmxV a)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSqrtEst(a);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(sqrtf4fast(a.get128()));
#endif
}
/*************************************************************
* vmxVectRecip ()
*************************************************************/
__INLINE vmxV vmxVectRecip (vmxV a)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorReciprocal(a);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(recipf4(a.get128()));
#endif
}
/*************************************************************
* vmxVectRecipEst ()
*************************************************************/
__INLINE vmxV vmxVectRecipEst (vmxV a)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorReciprocalEst(a);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(recipf4fast(a.get128()));
#endif
}
/*************************************************************
* vmxVectRecipSqrt ()
*************************************************************/
__INLINE vmxV vmxVectRecipSqrt (vmxV a)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorReciprocalSqrt(a);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(rsqrtf4(a.get128()));
#endif
}
/*************************************************************
* vmxVectRecipSqrtEst ()
*************************************************************/
__INLINE vmxV vmxVectRecipSqrtEst (vmxV a)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorReciprocalSqrtEst(a);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(rsqrtf4fast(a.get128()));
#endif
}

/*************************************************************
* vmxVectDot ()
*************************************************************/
__INLINE vmxV vmxVectDot (vmxV a, vmxV b) 
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVector4Dot(a, b);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_dot4(a.get128(), b.get128()));
#endif
}
/*************************************************************
* vmxVectCross ()
*************************************************************/
__INLINE vmxV vmxVectCross (vmxV a, vmxV b)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVector3Cross(a, b);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4(vec_cross3(a.get128(), b.get128()));
#endif
}
/*************************************************************
* vmxVectLerp ()
*************************************************************/
__INLINE vmxV vmxVectLerp (vmxV a, vmxV b, vmxV t)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorLerpV(a, b, t);
#endif
#if defined(_AP_PS3)
   return vmxVectMadd(vmxVectSub(b, a), t, a);
#endif
}

//
// Vector Comparision
//
/*************************************************************
* vmxVectGreaterOrEqual ()
*************************************************************/
__INLINE vmxV vmxVectGreaterOrEqual (vmxV v1, vmxV v2)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorGreaterOrEqual(v1, v2);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_cmpge(v1.get128(), v2.get128()));
#endif
}
/*************************************************************
* vmxVectGreater()
*************************************************************/
__INLINE vmxV vmxVectGreater(vmxV v1, vmxV v2)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorGreater(v1, v2);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_cmpgt(v1.get128(), v2.get128()));
#endif
}
/*************************************************************
* vmxVectLess ()
*************************************************************/
__INLINE vmxV vmxVectLess (vmxV v1, vmxV v2)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorLess(v1, v2);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_cmplt(v1.get128(), v2.get128()));
#endif
}
/*************************************************************
* vmxVectSelect ()
*************************************************************/
__INLINE vmxV vmxVectSelect(vmxV v1, vmxV v2, vmxV control)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSelect(v1, v2, control);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_sel((vector unsigned char)v1.get128(), (vector unsigned char)v2.get128(), (vector unsigned char)control.get128()));
#endif
}
/*************************************************************
* vmxVectMin ()
*************************************************************/
__INLINE vmxV vmxVectMin(vmxV v1, vmxV v2)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorMin(v1, v2);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_min(v1.get128(), v2.get128()));
#endif
}
/*************************************************************
* vmxVectMax ()
*************************************************************/
__INLINE vmxV vmxVectMax(vmxV v1, vmxV v2)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorMax(v1, v2);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_max(v1.get128(), v2.get128()));
#endif
}
/*************************************************************
* vmxVectSaturate()
*************************************************************/
__INLINE vmxV vmxVectSaturate(vmxV v)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSaturate(v);
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)vec_max(vec_min(v.get128(), vmxVectOne().get128()), vmxVectZero().get128()));
#endif
}



//
// Vector misc functions
//
/*************************************************************
* vmxVectZero ()
*************************************************************/
__INLINE vmxV vmxVectZero (void)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorZero();
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)(0.f));
#endif
}
/*************************************************************
* vmxVectOne ()
*************************************************************/
__INLINE vmxV vmxVectOne (void)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMVectorSplatOne();
#endif
#if defined(_AP_PS3)
   return Aos::Vector4((vec_float4)(1.f));
#endif
}









//
// Matrix Load & store
//
/*************************************************************
* vmxMatrLoadA ()
*************************************************************/
__INLINE vmxMATR vmxMatrLoadA (float *src)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   STRONG_ASSERT(((DWORD)src) % 16 == 0);
   return XMLoadFloat4x4A((XMFLOAT4X4A*)src);
#endif
#if defined(_AP_PS3)
   return Aos::Matrix4R(Aos::Vector4((vec_float4)vec_ld(0, src)), 
                        Aos::Vector4((vec_float4)vec_ld(16, src)), 
                        Aos::Vector4((vec_float4)vec_ld(32, src)), 
                        Aos::Vector4((vec_float4)vec_ld(48, src)));
#endif
}
/*************************************************************
* vmxMatrLoadUA ()
*************************************************************/
__INLINE vmxMATR vmxMatrLoadUA (float *src)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMLoadFloat4x4((XMFLOAT4X4*)src);
#endif
#if defined(_AP_PS3)
   return Aos::Matrix4R(Aos::Vector4((vec_float4)vec_load_unaligned(src, 0)), 
                        Aos::Vector4((vec_float4)vec_load_unaligned(src, 16)), 
                        Aos::Vector4((vec_float4)vec_load_unaligned(src, 32)), 
                        Aos::Vector4((vec_float4)vec_load_unaligned(src, 48)));
#endif
}
/*************************************************************
* vmxMatrStoreA ()
*************************************************************/
__INLINE void vmxMatrStoreA (vmxMATR &m, float *dst)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   XMStoreFloat4x4A((XMFLOAT4X4A*)dst, m);
#endif
#if defined(_AP_PS3)
   vec_st(m.getRow0().get128(),  0, dst);
   vec_st(m.getRow1().get128(), 16, dst);
   vec_st(m.getRow2().get128(), 32, dst);
   vec_st(m.getRow3().get128(), 48, dst);
#endif
   return;
}
/*************************************************************
* vmxMatrStore3A ()
*************************************************************/
__INLINE void vmxMatrStore3A (vmxMATR &m, float *dst)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   XMStoreFloat4A((XMFLOAT4A*)dst+0, m.r[0]);
   XMStoreFloat4A((XMFLOAT4A*)dst+1, m.r[1]);
   XMStoreFloat4A((XMFLOAT4A*)dst+2, m.r[2]);
#endif
#if defined(_AP_PS3)
   vec_st(m.getRow0().get128(),  0, dst);
   vec_st(m.getRow1().get128(), 16, dst);
   vec_st(m.getRow2().get128(), 32, dst);
#endif
   return;
}
/*************************************************************
* vmxMatrStoreA ()
*************************************************************/
__INLINE void vmxMatrStoreUA (vmxMATR &m, float *dst)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   XMStoreFloat4x4((XMFLOAT4X4*)dst, m);
#endif
#if defined(_AP_PS3)
   vec_store_unaligned(m.getRow0().get128(), dst,  0);
   vec_store_unaligned(m.getRow1().get128(), dst, 16);
   vec_store_unaligned(m.getRow2().get128(), dst, 32);
   vec_store_unaligned(m.getRow3().get128(), dst, 48);
#endif
}

//
// Matrix operations
//
/*************************************************************
* vmxMatrTranspose ()
*************************************************************/
__INLINE vmxMATR vmxMatrTranspose (vmxMATR &m)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMMatrixTranspose(m);
#endif
#if defined(_AP_PS3)
   return Aos::transpose(m);
#endif
}
/*************************************************************
* vmxMatrIdentity ()
*************************************************************/
__INLINE vmxMATR vmxMatrIdentity (void)
{
#if defined(_AP_PC) || defined(_AP_XENON)
   return XMMatrixIdentity();
#endif
#if defined(_AP_PS3)
   return Aos::Matrix4R::identity();
#endif
}





//
// End of file 'M3D_VMX.HPP'
//
